package netty;

import cn.hutool.core.date.DateUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.util.concurrent.TimeUnit;

@Slf4j
public class NettyHeatBeatCase {
    private static final  int PORT =6668;
    
    @Test
    public void headBeatServer(){
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup(4);
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        try {
            serverBootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            
                            // 提供一个空闲状态得处理器
                            // 当触发事件之后，将会通过管道，发给下一个handle进行处理
                            pipeline.addLast(new IdleStateHandler(3,5,7, TimeUnit.SECONDS));
                            // 加入 一个自定义处理器，进一步对 空闲状态进行处理
                            pipeline.addLast(new HeatBeatServerHandle());
                        }
                    });
            log.error("服务器 准备完成");
            ChannelFuture cf = serverBootstrap.bind(PORT).sync();

            cf.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

    /**
     * todo nacos 可能就是这样的机制
     */
    private static class HeatBeatServerHandle extends ChannelInboundHandlerAdapter{
        /** 此回调，就是处理 IdleStateHandler 定义的三种事件。
         * @param ctx 上下文
         * @param evt 事件类型
         * @throws Exception
         */
        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            if (evt instanceof IdleStateEvent){
                IdleStateEvent event = (IdleStateEvent) evt;
                String state ="";
                switch (event.state()){
                    case READER_IDLE:
                        state ="读空闲";
                        break;
                    case WRITER_IDLE:
                        state ="写空闲";
                        break;
                    case ALL_IDLE:
                        state = "读写空闲";
                        break;
                }
                log.error("客户端：{},在{},发生了{}",ctx.channel().remoteAddress(), DateUtil.now(),state);
            }
        }
    }
}
